#!/usr/bin/env ruby

# CSV to USF Converter, version 0.12, 06/11/2008
# Copyright (c) 2008, Hanjo Kim
# Released under the GPL

# Changelog
# 2008.11.04 : ver 0.1 - Initial version
# 2008.11.05 : ver 0.11
#  1. '-i' and '-o' options are required now.
#  2. change -d option parsing routine
#  3. Verificate the existence of dependent variable called by -d option
#  4. Minor changes in error messages
# 2008.11.06 : ver 0.12
#  1. -d option is required now.
#  2. More information about program itself

# TODO
# 1. Support other separator than comma in csv file.
# 2. Validation of csv format (by FasterCSV?)

require 'rubygems'
require 'fastercsv'
require 'choice'

PROGRAM_VERSION = 0.12

## Option parsing with choice
Choice.options do
	banner "CSV2UFS, version " + PROGRAM_VERSION.to_s + "\n"
	banner "Copyright (c) 2008 Hanjo Kim\n"
	banner "This program is distributed under GPLv3.\n"
	banner "See http://cheminformatics-snippets.googlecode.com for more details."
	banner ''

	header ''
	header 'Specific options:'

	option :dep do
		short '-d'
		long '--dep NAME'
		desc 'Required. The name of dependent variable (usually activity). If no, then use \'-d NONE\'.'
	end

	option :input	do
		short '-i'
		long '--input FILENAME'
		desc 'Required. The name of input file (required)'
	end

	option :output do
		short '-o'
		long '--output FILENAME'
		desc 'Required. The name of ouput file'
	end

	option :star do
		short '-s'
		long '--star'
		desc 'Optional. Remove trailing star(s) from PreADMET generated csv file'
	end

	option :help do
		short '-h'
		long '--help'
		desc 'Show this message'
	end

	option :version do
		short '-v'
		long '--version'
		desc 'Show version'
		action do
			puts "CSV2UFS version #{PROGRAM_VERSION}"
			exit
		end
	end
end

class Csv2ufs
	def initialize
		@inp = Choice.choices[:input]
		@ext = File.extname(@inp)
		@fn = File.basename(@inp)
		@dep = Choice.choices[:dep]
		@output = Choice.choices[:output]
	end

	def verify_input
		File.exist?(@inp) and @ext == '.csv'
	end

	def csv_process
		@csv = FasterCSV.read(@inp, options={:headers => true})
		@headers = @csv.headers
		unless @headers.include?(@dep)
			puts "Error: \"#{@dep}\" descriptor doesn't exist. Please verify your input."
			exit
		end
	end

	def format_file
		dep_index = nil
		dep_index = @headers.index(@dep) unless @dep == 'NONE' #index of dependent variable

		@comments = "# Converted by csv2ufs.\n# Source file: #{@inp}"

		activity = ''
		nrow = @csv.size
		if @dep == nil
			ncol = @headers.size
			activity = ''
		else
			ncol = @headers.size - 1
			activity = '1'
		end
		@pars = "[PARS]\n#{nrow} #{ncol} #{activity}"

		hd = @headers.delete_at(dep_index) # delete dependent variable 
		@headers.insert(0, hd).insert(0, "id") # move dependent variable in front of array, and insert "id" string
		hline = @headers.join(" ")
		@cols = "[COLS]\n#{hline}"

		# Make [DATA] part
		# 1. delete header line
		a = @csv.to_a.reverse
		a.pop
		b = a.reverse
		# 2. compose data array
		index = 1
		b.each do |array|
			# -s option deletes trailing star(s)
			unless Choice.choices[:star] == nil
				array.collect! {|x| x.gsub(/\*+$/, '')}
			end
			# move dependent variable in front of array, and insert index number
			if dep_index			
				dep = array.delete_at(dep_index)
				array.insert(0, dep)
			end
			array.insert(0, index)
			index = index + 1
		end
		@data = ''
		b.each do |line|
			@data << line.join(",") << "\n"
		end
	end

	def write_input
		format_file
		@content = @comments + "\n\n" + @pars + "\n\n" + @cols + "\n\n" + "[DATA]\n" + @data
		File.open(@output, 'w+') do |file|
			file << @content
		end
	end
end

if ARGV.empty?
	puts "Error: No option specified. Please use '--help' option to see the usage."
else
	conv = Csv2ufs.new
	if conv.verify_input
		conv.csv_process
		conv.write_input
		puts "Output file is wrritten successfully!"
	else
		puts "Error: Can't find input file: #{Choice.choices[:input]}"
	end
end
